/**
  * @file 		appss.c
  * @brief		应用支持子层，为应用层提供服务和管理。
  *
  * @copyright  Copyright (c) 2020~2030 ShenZhen Dxtc Technology Co., Ltd. 
  * All rights reserved.
  *
  * @version	v3.1
  * @author		FengLi
  * @date 		2021-08-02
  *
  * @note		鼎新同创·智能锁
  * 
  * @par 修改日志:
  * <1> 2021/08/02 v3.1 FengLi 创建初始版本
  *******************************************************************/
#include "osal.h"
#include "osport.h"
#include "device.h"
#include "component.h"

#ifndef KOS_PARAM_API_MAX_QTY
/** @brief   系统API最大数量 */
#define	KOS_PARAM_API_MAX_QTY     80
#endif

/** @brief   用于断言的作用 */
#define APPSS_ASSERT( x ) if ((x) == 0) { __OSAL_LOG("[appss.c:%05d] ASSERT\r\n", __LINE__); Device_EnterCritical(); for( ;; ); }

#if !defined(KOS_PARAM_ROLE_SLAVE)

/** @brief   虚拟TASK结构 */
typedef struct
{
    uint8_t comp_id;     ///< 组件ID
    uint8_t alias;       ///< 组件昵称
    uint8_t status;      ///< 组件状态
    uint8_t nv_size;     ///< 组件NV-SIZE
    uint8_t nv_data[OSPORT_vTASK_NV_SIZE];  ///< 组件NV数据域
}vTaskList_stu_t;

/** @brief   虚拟端口任务表结构 */
typedef struct
{
    VirtualHardware_enum_t port;         ///< 虚拟TASK-list对应的端口
    uint8_t qty;                         ///< 虚拟TASK数量
    vTaskList_stu_t list[OSPORT_vTASK_MAX_QTY]; ///< vTask-list
}VirtualTask_stu_t;

/** @brief  虚拟任务表（从系统的TASK-LIST） */
__EFRAM static VirtualTask_stu_t vTaskList[OSPORT_MAX_QTY];

/** @brief  等待同步的PORT */
static VirtualHardware_enum_t wait_synch_port[OSPORT_MAX_QTY]; 

static uint32_t sub_wake_id = 0xFF;              ///< 从机唤醒源的ID
static uint32_t sub_wake_param = 0;              ///< 从机唤醒源的参数
#endif

/** @brief   订阅的消息节点 */
typedef struct __SubMsg
{
    uint16_t comp_id;             ///< 订阅的组件ID
    void (*cb)(void*, uint16_t);  ///< 回调函数
    struct __SubMsg *next;        ///< 指向下一个节点地址的结构域
}SubMsg_stu_t;

/** @brief   应用控制块结构 */
typedef struct __AppCtrlBlock
{
    char *name;                    ///< 应用名称
    FunctionalState state;         ///< 应用状态
    ErrorStatus (*sleep_cb)(void); ///< 休眠回调
    SubMsg_stu_t *sub_msg;         ///< 已订阅的消息

    struct __AppCtrlBlock *next;   ///< 指向下一个控制块地址的结构域
}AppCtrlBlock_stu_t;

/** @brief  OSAL消息类型 */
typedef struct __MsgType
{
	struct __MsgType *next;  ///< 指向下一个消息地址的结构域
	struct __MsgType *prev;  ///< 指向前一个消息地址的结构域
	uint16_t comp_id;        ///< 组件ID（消息发布者）
    uint16_t len;            ///< 消息长度
    uint8_t msg[];           ///< 消息内容
}MesgHeadType_stu_t;

/** @brief  SYS API表 */
typedef struct 
{
    char *name;        ///< API函数名称
    void *fn;          ///< API函数地址
    uint16_t comp_id;  ///< API所属的组件ID
    uint16_t app_id;   ///< API所属的APP-ID
}SysApiInfo_stu_t;

/** @brief  定义一个SYS—API表 */
static SysApiInfo_stu_t api_list[KOS_PARAM_API_MAX_QTY] = {0};

static uint16_t bak_activeAppIndex;   ///<  执行SYS-API时用来备份当前活跃的APP-INDEX
static uint16_t bak_activeTaskIndex;  ///<  执行SYS-API时用来备份当前活跃的TASK-INDEX

static AppCtrlBlock_stu_t *pAppList = NULL;  ///<  应用层链表指针  

static MesgHeadType_stu_t *pMessageList = NULL;  ///< 消息表指针

static FlagStatus osal_start_flag = RESET;  ///<  系统第一次启动后，会设置成SET   

extern uint8_t g_TaskQty;
extern uint16_t g_ActiveTaskIndex;
extern uint16_t g_ActiveAppIndex;
extern FlagStatus g_SystemResetFlag;

extern ErrorStatus OSAL_TaskStatusCheckLocal(void);
extern uint16_t OSAL_TaskIndex2CompId(uint16_t task_index);
extern void OSAL_RefreshSleepTime(uint32_t time, uint32_t param);
extern ErrorStatus OSAL_MboxPostLocal(uint16_t comp_id, uint8_t alias, void *msg, uint16_t size);
extern ErrorStatus OSAL_NvGetInfo(uint16_t comp_id, uint8_t alias, uint32_t *addr, uint32_t *size);
__attribute__((weak)) void OSAL_LoopHook(void);

static void OSAL_MessageListInit(void);


#if !defined(KOS_PARAM_ROLE_SLAVE)
 /**
  *@brief       检查vTASK的同步情况
  *@details     详细说明：检查子设备的vTASK的同步情况
  *
  *@return     【SUCCEE】：成功   【ERROR】：失败（错误）
  */
static ErrorStatus OSAL_vTaskCheckSynch(void)
{
    for (int i=0; i<OSPORT_MAX_QTY; i++)
    {
        if (wait_synch_port[i] != 0)
        {
            return ERROR;
        }
    }
    return SUCCESS;
}

/**
  * @brief   等待vTASK同步完成
  * @details 详细说明：无
  *         
  * @note    主机首次上电启动应用层前，会调用本函数
  * @return  NULL
  */
static void OSAL_vTaskWaitSynch(void)
{
    uint32_t delay = 0;
    VirtualHardware_enum_t (*hwl_port)[2];

    /* 获取底层已注册的PORT */
    hwl_port = (VirtualHardware_enum_t (*)[2])(Device_GetDeviceCtrlBlock(vCPU)->devParam);
    if (hwl_port == 0)
    {
        return;
    }
    for (int i = 0; (i < OSPORT_MAX_QTY) && (hwl_port[i][0] != vNOHARDWARE); i++)
    {
        //< vBLE端口不等待同步
        if ((DeviceType_enum_t)(hwl_port[i][0] >> 8) != vBLE)
        {
            wait_synch_port[i] = hwl_port[i][0];
        }
    }

    /* 发送HELLO命令、等待所有PORT的TASK-INFO同步完成 */
    while ((OSAL_vTaskCheckSynch() == ERROR) && (delay < 1000))
    {
        if (delay % 200 == 0)
        {
            for (int i = 0; i < OSPORT_MAX_QTY; i++)
            {
                if (wait_synch_port[i] != (VirtualHardware_enum_t)0)
                {
                    uint32_t rm = 0;
                    #ifdef KOS_PARAM_OSPORT_CRYPTO
                    rm = OSAL_OsportCreateRm(wait_synch_port[i], 1);
                    __OSAL_LOG("[appss.c] Send hello, Port:%04X Rm:%08X\r\n", wait_synch_port[i], rm);
                    #endif
                    OSAL_OsPortSend(wait_synch_port[i], OSPORT_CMD_HELLO, 0xFF, 0, &rm, sizeof(rm));
                }
            }
        }
        OSAL_OsPortProcess();
        Device_DelayUs(500);
        Device_DelayUs(500);
        Device_FeedDog();
        delay++;
    }
    memset(wait_synch_port, 0, sizeof(wait_synch_port));
}

/**
  * @brief   同步虚拟TASK
  * @details 详细说明：收到了从机发来的TASK-INFO命令
  *         
  * @param[in]  port：端口
  * @param[in]  qty：任务数量
  * @param[in]  opt：0：同步整个虚拟表   1：同步某一个TASK
  * @param[in]  data：任务表数据：COMP-ID  ALIAS  STA  NV-SIZE  NV-DATA  COMP-ID  ALIAS  STA  NV-SIZE  NV-DATA  ……
  * 
  * @return       NULL
  */
static void OSAL_vTaskSynch(VirtualHardware_enum_t port, uint8_t qty, uint8_t opt, uint8_t *data)
{
    if (opt == 0) //< 同步一个端口的所有TASK
    {
        int index = 0xFF, cnt = 0;

        for (int i=0; i<OSPORT_MAX_QTY; i++)
        {
            /* 清掉旧表数据 */
            if (vTaskList[i].port == port)
            {
                vTaskList[i].port = (VirtualHardware_enum_t)0;
                vTaskList[i].qty = 0;
            }

            /*  清掉wait_synch_port里面对应的port */
            if (port == wait_synch_port[i])
            {
                wait_synch_port[i] = (VirtualHardware_enum_t)0;
            }

            /* 记录空闲的索引 */
            if (index == 0xFF && vTaskList[i].port == 0)
            {
                index = i; 
            }
        }

        /*  填充新表 */ 
        __OSAL_LOG(C_LIGHT_GREEN "[appss.c] vTASK-LIST: %04X\r\n", port);
        for (int i = 0; (i < qty) && (i < OSPORT_vTASK_MAX_QTY); i++)
        {
            vTaskList[index].list[i].comp_id = data[cnt++];
            vTaskList[index].list[i].alias   = data[cnt++];
            vTaskList[index].list[i].status  = data[cnt++];
            vTaskList[index].list[i].nv_size = data[cnt++];
            APPSS_ASSERT(vTaskList[index].list[i].nv_size <= OSPORT_vTASK_NV_SIZE);
            memcpy(vTaskList[index].list[i].nv_data, &data[cnt], vTaskList[index].list[i].nv_size);
            cnt += vTaskList[index].list[i].nv_size;
            
            __OSAL_LOG("vTASK_INDEX:%-3d   COMP_ID:%-3d   ALIAS:%-3d   NV_SIZE:%-5d\r\n", 
                       i, vTaskList[index].list[i].comp_id, vTaskList[index].list[i].alias, vTaskList[index].list[i].nv_size);
        }
        __OSAL_LOG(C_NONE "\r\n");
        vTaskList[index].port = port;
        vTaskList[index].qty = (qty > OSPORT_vTASK_MAX_QTY) ? OSPORT_vTASK_MAX_QTY : qty;
    }
    else if (opt == 1 && qty == 1)//< 同步某一个TASK的NV
    {
        int index;
        for (index = 0; index < OSPORT_MAX_QTY; index++)
        {
            if (vTaskList[index].port == port)
            {
                break;
            }
        }

        if (index == OSPORT_MAX_QTY)
        {
            return;
        }

        for (int i=0; i<vTaskList[index].qty; i++)
        {
            uint8_t comp_id = data[0];
            uint8_t alias   = data[1];
            uint8_t status  = data[2];
            uint8_t nv_size = data[3];
            if (comp_id == vTaskList[index].list[i].comp_id && alias == vTaskList[index].list[i].alias && nv_size == vTaskList[index].list[i].nv_size)
            {
                vTaskList[index].list[i].status  = status;
                memcpy(vTaskList[index].list[i].nv_data, &data[4], nv_size);
                __OSAL_LOG("vTask info synch, comp_id:%d\r\n", comp_id);
            }
        }
    }
}

/**
  * @brief    根据组件ID和昵称，查找这个虚拟TASK对应的端口
  * @details  详细说明：无
  *         
  * @param[in]  comp_id：组件ID
  * @param[in]  alias：组件昵称
  *         
  * @return 返回端口号
  */
static VirtualHardware_enum_t OSAL_vTaskFindPort(uint16_t comp_id, uint8_t alias)
{
    for (int i=0; i<OSPORT_MAX_QTY; i++)
    {
        for (int j=0; j<vTaskList[i].qty; j++)
        {
            if ((comp_id == vTaskList[i].list[j].comp_id) && 
                ((alias == vTaskList[i].list[j].alias) || (0 == vTaskList[i].list[j].alias)))
            {
                return vTaskList[i].port;
            }
        }
    }
    return vNOHARDWARE;
}

/**
 * @brief 获取从机端口状态
 * 
 * @param channel 底层cpu.c里面注册的vhw_osport通道号
 * @return int -1：通道不存在
 *              1：该通道的从机握手失败
 *              0：该通道的从机握手正常（已同步vTask）
 */
int OSAL_GetSlaveStatus(int channel)
{
    int qty = 0;
    VirtualHardware_enum_t (*hwl_port)[2];

    hwl_port = (VirtualHardware_enum_t (*)[2])(Device_GetDeviceCtrlBlock(vCPU)->devParam);
    if (hwl_port == 0)
    {
        return -1;
    }

    for (qty = 0; qty < OSPORT_MAX_QTY; qty++)
    {
        if (hwl_port[qty][0] == vNOHARDWARE)
        {
            break;
        }
    }

    if (channel >= qty)
    {
        return -1; //通道不存在
    }

    if ((DeviceType_enum_t)(hwl_port[channel][0] >> 8) == vBLE)
    {
        return 0;  //BLE通道不用管
    }

    for (int i = 0; i < OSPORT_MAX_QTY; i++)
    {
        if (vTaskList[i].port == hwl_port[channel][0])
        {
            return 0;
        }
    }
    return 1;
}
#endif

//! /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
  * @brief   APP初始化列表头部
  * @details 详细说明：通过定义一个空函数来指向APP初始化的列表头部 
  * 
  * @return NULL       
  */
static void OSAL_AppInitTable_Start(uint32_t wake_id, uint32_t wake_param)
{
    return;
}

/** @brief   挂载APP初始化入口（首端）函数 */
APP_INIT_START_EXPORT(OSAL_AppInitTable_Start);

/**
  * @brief   APP初始化列表尾部
  * @details 详细说明：通过定义一个空函数来指向APP初始化的列表尾部
  * 
  * @return NULL          
  */
static void OSAL_AppInitTable_End(uint32_t wake_id, uint32_t wake_param)
{
    return;
}

/** @brief   挂载APP初始化出口（末端）函数 */
APP_INIT_END_EXPORT(OSAL_AppInitTable_End);

/**
  * @brief  往指定app的订阅表添加一个节点
  * @details  详细说明：通过控制块句柄定位具体的APP
  *         
  * @param[in]  handle：app控制块指针
  * @param[in]  comp_id：订阅的组件ID
  * @param[in]  cb：订阅消息回调函数
  *         
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误）
  */
static ErrorStatus OSAL_AppAddSubscribe(AppHandle_t handle, uint16_t comp_id, void(*cb)(void*, uint16_t))
{
    AppCtrlBlock_stu_t *pApp = (AppCtrlBlock_stu_t *)handle;

    if (pApp->sub_msg == NULL)
    {
        pApp->sub_msg = (SubMsg_stu_t *)OSAL_Malloc(sizeof(SubMsg_stu_t));
        if (pApp->sub_msg != NULL)
        {
            pApp->sub_msg->next = NULL;
            pApp->sub_msg->comp_id = comp_id;
            pApp->sub_msg->cb = cb;
            return SUCCESS;
        }
    }
    else
    {
        SubMsg_stu_t *pMsg = pApp->sub_msg;

        if (pMsg->comp_id == comp_id)
        {
            return SUCCESS; //< 已订阅
        }

        for (; pMsg->next != NULL; pMsg = pMsg->next)
        {
            if (pMsg->next->comp_id == comp_id)
            {
                return SUCCESS; //< 已订阅
            }
        }
        pMsg->next = (SubMsg_stu_t *)OSAL_Malloc(sizeof(SubMsg_stu_t));
        if (pMsg->next != NULL)
        {
            pMsg->next->next = NULL;
            pMsg->next->comp_id = comp_id;
            pMsg->next->cb = cb;
            return SUCCESS;
        }
    }
    return ERROR;
}

/**
  * @brief    查找APP的订阅表
  * @details  详细说明：无
  *    
  * @param[in]  comp_id：源任务ID
  * @param[in]  sub_msg：订阅表头节点地址
  *         
  * @return 返回匹配的订阅表节点地址
  */
static SubMsg_stu_t *OSAL_AppFindSubscribe(uint16_t comp_id, SubMsg_stu_t *sub_msg)
{
    for (; sub_msg!=NULL; sub_msg=sub_msg->next)
    {
        if (comp_id == sub_msg->comp_id)
        {
            return sub_msg;
        }
    }
    return NULL;
}

/**
  * @brief    应用层订阅消息回调
  * @details  详细说明：将消息推给应用层
  *   
  * @param[in]  comp_id：当前这个消息的源任务ID
  * @param[in]  pMsg：消息实体的地址
  * @param[in]  len：消息长度
  *         
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误）
  */
static void OSAL_AppSubMessageCb(uint16_t comp_id, void *msg, uint16_t len)
{
    AppCtrlBlock_stu_t *pApp = pAppList;
    
    pApp = pApp->next;
    for (int id=0; pApp!=NULL; pApp=pApp->next , id++)
    {
        if (pApp->state != ENABLE)
        {
            continue;
        }

        SubMsg_stu_t *pMsg = OSAL_AppFindSubscribe(comp_id, pApp->sub_msg);
        if (pMsg != NULL)
        {
            g_ActiveAppIndex = id;
            pMsg->cb(msg, len);
            g_ActiveAppIndex = APP_NO_APP;
        }
    }
}

/**
  * @brief  执行应用层的休眠回调函数
  * @details  详细说明：无  
  *         
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误）
  */
static ErrorStatus OSAL_SleepCallbackApp(void)
{
    AppCtrlBlock_stu_t *pApp = pAppList;

    pApp = pApp->next;
    for (int index = 0; pApp != NULL; pApp = pApp->next, index++)
    {
        if (pApp->sleep_cb == NULL)
        {
            continue;
        }

        g_ActiveAppIndex = index;
        if (pApp->sleep_cb() != SUCCESS)
        {
            g_ActiveAppIndex = APP_NO_APP;
            return ERROR;
        }
        g_ActiveAppIndex = APP_NO_APP;
    }
    return SUCCESS;
}

/**
  * @brief    执行应用层入口函数
  * 
  * @return   NULL    
  */
void OSAL_AppMain(uint32_t wake_id, uint32_t wake_param)
{
    const App_Init_fn_t *fn_ptr = &__App_Init_OSAL_AppInitTable_Start;
    fn_ptr++;
    g_ActiveAppIndex = 0;
    for (; fn_ptr < &__App_Init_OSAL_AppInitTable_End; fn_ptr++)
    {
        (*fn_ptr)(wake_id, wake_param);
        g_ActiveAppIndex++;
    }
    g_ActiveAppIndex = APP_NO_APP;
    osal_start_flag = SET;
}

#if !defined(KOS_PARAM_ROLE_SLAVE)
static uint32_t g_time_start = 0; ///< rtc计时起始时间

/**
  * @brief    rtc测量结束
  * @details  详细说明：无
  * 
  * @param[in] handle：定时器句柄
  * 
  * @return   NULL    
  */
static void _timing_measurement_rtc(TimerHandle_stu_t handle)
{
    uint32_t time_end = 0;
    uint8_t err = 0;
    OSAL_TimeGet(&time_end, T_UTC);
    __OSAL_LOG("[appss.c] time: %ld, %ld\r\n", time_end, g_time_start);
    if (time_end == g_time_start)
    {
        err = 1;
    }
    uint16_t index_bak = g_ActiveAppIndex;
    g_ActiveTaskIndex = 0;
    OSAL_MessagePublishErrorCode(ERRCODE_TYPE_RTC, err);
    g_ActiveTaskIndex = index_bak;
}

/**
  * @brief    启动应用层 -- 主机端
  * @details  详细说明：无
  * 
  * @param[in] id: 唤醒源的ID，也可以理解为组件ID
  * @param[in] param:唤醒源参数
  * 
  * @return   NULL    
  */
void OSAL_AppStart(uint32_t id, uint32_t param)
{
    uint32_t wake_id = id;
    uint32_t wake_param = param;

    //< rtc测量，此处为起始时间，创建一个2s的定时器运行作为结束时间
    OSAL_TimeGet(&g_time_start, T_UTC);
    OSAL_TimerCreate(_timing_measurement_rtc, 2000, RESET);

    __OSAL_LOG("[appss.c] OSAL_AppStart\r\n");

    if (wake_id == 0xFF)
    {
        //< 主机上电启动：等待所有端口完成同步SYNC
        OSAL_vTaskWaitSynch();
    }
    else if (wake_id == TASK_ID_IDLE && wake_param != 1)
    {
        //< 被从机唤醒唤醒：给所有从机都发一个hello，全部叫醒
        OSAL_OsPortSend(vNOHARDWARE, OSPORT_CMD_HELLO, (uint8_t)wake_id, (uint8_t)wake_param, NULL, 0);

        sub_wake_id = 0xFF;
        if ((wake_param >> 8) == vBLE)
        {
            wait_synch_port[0] = (VirtualHardware_enum_t)wake_param;
        }

        //< 等待从机交互完成
        for (int t = 0; t < 10000; t++)
        {
            OSAL_LoopHook();
            OSAL_OsPortProcess();
            if ((wake_param >> 8) == vBLE) 
            {
                //< 被BLE类型的从机唤醒：要等待SYNC同步完成
                if (OSAL_vTaskCheckSynch() != ERROR)
                {
                    break;
                }
            }
            else
            {
                //< 被普通类型的从机唤醒：收到wake_id就结束等待
                if (sub_wake_id != 0xFF)
                {
                    break; 
                }
            }
            Device_DelayUs(100);
            Device_FeedDog();
        }

        //< 判断wake_id是否正确
        if (sub_wake_id != 0xFF)
        {
            wake_id = sub_wake_id;
            wake_param = sub_wake_param;
        }
        else
        {
            __OSAL_LOG("[appss.c] sub_wake_id error\r\n");
        }
    }
    else
    {
        //< 主机自己唤醒
        OSAL_OsPortSend(vNOHARDWARE, OSPORT_CMD_HELLO, (uint8_t)wake_id, (uint8_t)wake_param, NULL, 0);
    }
    OSAL_AppMain(wake_id, wake_param);
}
#endif

/**
  * @brief  APP链表表初始化
  * @details  详细说明：申请APP控制块内存并清空，初始消息列表
  * 
  * @return   NULL         
  */
void OSAL_ApplicationInit(void)
{
    pAppList = (AppCtrlBlock_stu_t *)OSAL_Malloc(sizeof(AppCtrlBlock_stu_t));
    APPSS_ASSERT(pAppList != NULL);
    memset(pAppList, 0, sizeof(AppCtrlBlock_stu_t));

    OSAL_MessageListInit();
}

/**
  * @brief  获取app的状态
  * @details  详细说明：无
  *         
  * @param[in]  app_id：需要获取的APP-ID
  * 
  * @return 【0】:禁能    【1】:使能    【-1】:错误（app不存在）
  */
int OSAL_AppStateGet(uint32_t app_id)
{
    AppCtrlBlock_stu_t *pApp = pAppList;

    if (pApp == NULL)
    {
        return -1;
    }
    
    pApp = pApp->next;
    for (int id=0; pApp != NULL; pApp = pApp->next, id++)
    {
        if (app_id == id)
        {
            return ( (pApp->state == ENABLE) ? 1 : 0 );
        }
    }
    return -1;
}

/**
  * @brief  设置APP的状态
  * @details  详细说明：无
  *    
  * @param[in]  app_name：app名称
  * @param[in]  state：状态，ENABLE/DISABLE
  *         
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误）
  */
void OSAL_AppStateSet(char *app_name, FunctionalState state)
{
    AppCtrlBlock_stu_t *pApp = pAppList;

    pApp = pAppList->next;
    for (; pApp != NULL; pApp = pApp->next)
    {
        if ( (app_name == NULL) || (strcmp(app_name, pApp->name) == 0))
        {
            pApp->state = state;
        }
    }
}

/**
  * @brief  创建一个APP
  * @details  详细说明：只能在APP层调用
  * 
  * @param[in]  app_name：app名称
  * @param[in]  pSleepCb：APP休眠回调
  *         
  * @return 返回ACB地址（APP句柄）
  */
AppHandle_t OSAL_AppCreate(char *app_name, ErrorStatus(*pSleepCb)(void))
{
    AppCtrlBlock_stu_t *pApp = pAppList;

    APPSS_ASSERT((app_name != NULL) && (g_ActiveAppIndex != APP_NO_APP));

    for (; pApp->next != NULL; pApp = pApp->next)
    {
        if (strcmp(pApp->next->name, app_name) == 0)
        {
            return (void*)(pApp->next);//< 已创建
        }
    }

    pApp->next = (AppCtrlBlock_stu_t *)OSAL_Malloc(sizeof(AppCtrlBlock_stu_t));
    if (pApp->next != NULL)
    {
        pApp = pApp->next;
        pApp->next = NULL;

        pApp->name = app_name;
        pApp->sleep_cb = pSleepCb;
        pApp->sub_msg = NULL;
        pApp->state = ENABLE;
        return (void*)pApp;
    }
    return NULL;
}
//! /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
  * @brief  创建一个API
  * @details  详细说明：通过函数昵称以及函数地址来创建一个函数
  * 
  * @param[in]  name：API函数名称
  * @param[in]  fn：函数地址
  * 
  * @return   返回与name对应(也是输入)的函数地址
  */
void *OSAL_ApiCreate(char *name, void *fn)
{
    /* 系统第一次启动的过程中才允许创建API  */
    if (osal_start_flag != RESET)
    {
        return NULL; 
    }

    /* 创建API */
    for (int i=0; i<KOS_PARAM_API_MAX_QTY; i++)
    {
        if (api_list[i].fn == NULL)
        {
            api_list[i].name = name;
            api_list[i].fn = fn;
            api_list[i].app_id = g_ActiveAppIndex;
            api_list[i].comp_id = g_ActiveTaskIndex;
            return fn;
        }
    }
    __OSAL_LOG(C_LIGHT_RED C_COLOR "OSAL_ApiCreate error, %s\r\n" C_NONE, name);
    return NULL;
}

/**
  * @brief    API-CALL结束
  * @details  详细说明：恢复当前系统活跃的APP-ID
  * 
  * @return   NULL
  */
void OSAL_ApiCallStop(void)
{
    g_ActiveAppIndex = bak_activeAppIndex;
    g_ActiveTaskIndex = bak_activeTaskIndex;
}

/**
  * @brief   API-CALL开始
  * @details 详细说明：根据API名称查找函数地址
  * 
  * @param[in]  name：API函数名称
  * 
  * @return 返回与name对应的函数地址
  */
void *OSAL_ApiCallStart(char *name, char *path)
{
    if (strstr(path, "APP_") == NULL)
    {
        /* 非应用层调用：进断言 */
        APPSS_ASSERT(0);
    }

    /* 查找与name对应的函数地址 */
    for (int i=0; i<KOS_PARAM_API_MAX_QTY; i++)
    {
        if (strcmp(name, api_list[i].name) == 0)
        {
            bak_activeAppIndex = g_ActiveAppIndex;
            bak_activeTaskIndex = g_ActiveTaskIndex;

            g_ActiveAppIndex = api_list[i].app_id;
            g_ActiveTaskIndex = api_list[i].comp_id;
            return api_list[i].fn;
        }
    }
    return NULL;
}
//! /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
  * @brief  在消息链表的末尾添加一条消息
  * @details 详细说明：无
  *   
  * @param[in]  comp_id：组件id
  * @param[in]  data：消息内容
  * @param[in]  data：消息长度
  *         
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误）
  */
void OSAL_MessageAdd(uint16_t comp_id, uint8_t *data, uint16_t len)
{
	MesgHeadType_stu_t *pTemp = pMessageList;
    MesgHeadType_stu_t *pMsg = NULL;

    //< 申请消息空间
    pMsg = (MesgHeadType_stu_t*)OSAL_Malloc(sizeof(MesgHeadType_stu_t) + len);
    APPSS_ASSERT(pMsg != NULL);

    //< 填充消息内容
    pMsg->comp_id = comp_id;
    pMsg->len = len;
    memcpy(pMsg->msg, data, len);

    //< 消息节点挂到list
    for (; pTemp->next != NULL; pTemp = pTemp->next)
    {
        ;
    }
    pTemp->next = pMsg;
    pMsg->prev = pTemp;
    pMsg->next = NULL;
}

/**
  * @brief  删除消息链表里面的一条消息
  * @details 详细说明：无
  *    
  * @param[in]  pMsg：消息的首地址
  * 
  * @return NULL
  */
static void OSAL_MessageDelete(MesgHeadType_stu_t *pMsg)
{
	pMsg->prev->next = pMsg->next;
	if (pMsg->next != NULL)
	{
		pMsg->next->prev = pMsg->prev;
	}
	OSAL_Free(pMsg);
}

/**
  * @brief  初始化message链表
  * @details 详细说明：为消息列表数据块申请空间，将数据块内相关指针置0
  *        
  * @return NULL  
  */
static void OSAL_MessageListInit(void)
{
	pMessageList = (MesgHeadType_stu_t *)OSAL_Malloc(sizeof(MesgHeadType_stu_t));
    APPSS_ASSERT(pMessageList != NULL);

    pMessageList->next = NULL;
    pMessageList->prev = NULL;
}

/**
  * @brief  OSAL消息服务
  * @details 详细说明：将组件层发布的消息，推给APP层
  *         
  * @return NULL 
  */
void OSAL_MessageBroker(void)
{
	MesgHeadType_stu_t *pTemp = pMessageList;

	pTemp = pTemp->next;
	for (; pTemp != NULL; pTemp = pTemp->next)
	{
        OSAL_AppSubMessageCb(pTemp->comp_id, pTemp->msg, pTemp->len);

        pTemp = pTemp->prev;
        OSAL_MessageDelete(pTemp->next);
	}
}

/**
  * @brief  订阅消息（应用层订阅某个组件的消息）
  * @details 详细说明：只能在应用层调用
  * @param[in]  handle：app控制块指针（app句柄）
  * @param[in]  comp_id：订阅的源任务ID
  * @param[in]  cb：订阅消息回调函数
  *         
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误）
  */
ErrorStatus OSAL_MessageSubscribe(AppHandle_t handle, uint16_t comp_id, void(*cb)(void*, uint16_t))
{
    APPSS_ASSERT((g_ActiveAppIndex != APP_NO_APP) && (handle != NULL) && (cb != NULL));
    return OSAL_AppAddSubscribe(handle, comp_id, cb);
}

#if !defined(KOS_PARAM_ROLE_SLAVE)
/**
  * @brief   发布消息（主机端）
  * @details 详细说明: 将一条消息放到消息队列里面,且只能在TASK里面调用
  * 
  * @param[in]  pMsg：消息实体的地址
  * @param[in]  len：消息长度
  *         
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误)
  */
ErrorStatus OSAL_MessagePublish(void *msg, uint16_t len)
{
    APPSS_ASSERT((msg != NULL) && (len != 0) && (g_ActiveTaskIndex < g_TaskQty));

    if (g_SystemResetFlag == RESET)
    {
        //< PUBLISH 给本地应用层
        uint16_t comp_id;
        if (len & 0x8000)
        {
            len &= ~0x8000;
            comp_id = 0xF0;//COMP_SYS_MSG;
        }
        else
        {
            comp_id = OSAL_TaskIndex2CompId(g_ActiveTaskIndex);
        }
        OSAL_MessageAdd(comp_id, msg, len);
        return SUCCESS;
    }
    return ERROR;
}

uint8_t OSAL_MessageGetSource(uint8_t *esn)
{
    uint8_t devNum = 0;
    MesgHeadType_stu_t *pTemp = pMessageList;

    pTemp = pTemp->next;
    //printf("cur comp_id:%d\r\n",pTemp->comp_id);
    VirtualHardware_enum_t port = OSAL_vTaskFindPort(pTemp->comp_id, 0);
    //printf("port:%d\r\n",port);
#ifdef KOS_PARAM_OSPORT_CRYPTO
    devNum = OSAL_OsportSearchAccountInfo(port,esn);
#endif
    __OSAL_LOG("[appss.c] get msg source, cur comp_id: %d,port: %d,esn: %s,devnum:%d\r\n",pTemp->comp_id,port,esn,devNum);

    return devNum;
}
#endif

//! /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
  * @brief   发送一个消息到指定组件的邮箱
  * @details 详细说明: 只能在应用层调用
  * 
  * @param[in]  comp_id：组件ID
  * @param[in]  alias：组件昵称
  * @param[in]  msg：数据内容
  * @param[in]  size：数据大小
  *         
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误）
  */
ErrorStatus OSAL_MboxPost(uint16_t comp_id, uint8_t alias, void *msg, uint16_t size)
{
    ErrorStatus ret = ERROR;

    APPSS_ASSERT(g_ActiveAppIndex != APP_NO_APP);

    /* 发消息到本地TASK的邮箱  */
    if (OSAL_MboxPostLocal(comp_id, alias, msg, size) == SUCCESS)
    {
        ret = SUCCESS;
    }

#if !defined(KOS_PARAM_ROLE_SLAVE)
    /* 发消息到虚拟TASK的邮箱（子系统） */
    VirtualHardware_enum_t port = OSAL_vTaskFindPort(comp_id, alias);
    if (port != vNOHARDWARE)
    {
        ret = OSAL_OsPortSend(port, OSPORT_CMD_MBOX, comp_id, alias, msg, size);
        if (ret == SUCCESS)
        {
            __OSAL_LOG("[appss.c] Mbox post, comp_id:%d, alias:%d\r\n\r\n", comp_id, alias);
            if (OSAL_GetAutoSleepTime() < 1000)
            {
                __OSAL_LOG("[appss.c] Update sleep time 1000ms\r\n");
                OSAL_UpdateSleepTime(1000, 1);
            }
        }
    }
#endif
    return ret;
}

#if !defined(KOS_PARAM_ROLE_SLAVE)
/**
  * @brief  OSPORT状态改变---主机端
  *         
  * @param[in]  port：端口号
  * @param[in]  status：状态--离线、上线
  */
void OSAL_OsportStateChange(VirtualHardware_enum_t port, FlagStatus status)
{
    //< 端口离线清掉虚拟表
    if (status == RESET)
    {
        for (int i = 0; i < OSPORT_MAX_QTY; i++)
        {
            if (port == vTaskList[i].port)
            {
                memset(&vTaskList[i], 0, sizeof(vTaskList[i]));
            }
        }
    }
}

/**
  * @brief  处理OSPROT收到的命令 -- 主机端
  * @details 详细说明:无  
  * 
  * @param[in]  port：端口
  * @param[in]  cmd：命令字  
  * @param[in]  data：数据
  * @param[in]  len：数据长度
  *         
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误）
  */
void OSAL_ProcessOsportCmd(VirtualHardware_enum_t port, uint8_t cmd, uint8_t *data, uint16_t len)
{
    if (cmd == OSPORT_CMD_SYNC)
    {
        OSAL_vTaskSynch(port, data[0], data[1], data + 2);
        
    #ifdef KOS_PARAM_OSPORT_CRYPTO
        /* SYNC命令的最后8字节是Rm/Rs、 data[1]为0时表示同步所有信息 */
        if  (data[1] == 0)
        {
            uint32_t rm = 0, rs = 0;
            memcpy(&rm, data+len-8, 4);
            memcpy(&rs, data+len-4, 4);
            __OSAL_LOG("[appss.c] Port:%04X Rm:%08X Rs:%08X\r\n", port, rm, rs);
            OSAL_OsportSaveRmRs(port, rm, rs);
        }
    #endif
    }
    else if (cmd == OSPORT_CMD_PUBLISH && g_SystemResetFlag == RESET)
    {
        /* 
         * data[0]: comp_id
         * data[1]: alias
         */
        OSAL_MessageAdd(data[0], data + 2, len - 2);
    }
    else if (cmd == OSPORT_CMD_HELLO)
    {
        /* 
         * 主机收到从机HELLO握手：
         * 1、从机是上电启动、且当前主机没有处于等待同步vTASK的状态，就转发一次HELLO
         * 2、从机是BLE设备，不管是上电还是唤醒都转发一次HELLO
         */
        if ((data[0] == 0xFF && OSAL_vTaskCheckSynch() != ERROR) || ((DeviceType_enum_t)(port >> 8) == vBLE))
        {
            uint32_t number = 0, rm = 0;

        #ifdef KOS_PARAM_OSPORT_CRYPTO
            memcpy(&number, data+2, len-2);
            rm = OSAL_OsportCreateRm(port, number);
            __OSAL_LOG("[appss.c] Recv hello, Port:%04X number:%08X\r\n", port, number);
            __OSAL_LOG("[appss.c] Forward hello, create Rm:%08X\r\n", rm);
        #endif

            OSAL_OsPortSend(port, OSPORT_CMD_HELLO, 0xFF, 0xFF, &rm, sizeof(rm));
        }
        sub_wake_id = data[0];
        sub_wake_param = data[1];
    }
}

/**
  * @brief   更新休眠时间 （主机端）
  * @details 详细说明:无
  *         
  * @param[in]  time：时间值（ms）
  * @param[in]  param：1:休眠前执行回调，0:休眠前不执行回调
  * 
  * @return  NULL
  */
void OSAL_UpdateSleepTime(uint32_t time, uint32_t param)
{
    const uint32_t sleep_time = OSAL_GetAutoSleepTime();

    if ((abs(sleep_time - time) > 100) || (time == UINT32_MAX))
    {
        /* 刷新本地休眠时间 */
        OSAL_RefreshSleepTime(time, param);

        /* 给从机系统同步休眠时间 */
        OSAL_OsPortSend(vNOHARDWARE, OSPORT_CMD_UPDATE_SLEEP, param, 0, &time, sizeof(time));
    }
}

/**
  * @brief  获取指定组件的NV数据
  * @details 详细说明:仅允许应用层调用、可以读取子系统的NV数据
  *         
  * @param[in]  comp_id：组件ID
  * @param[in]  alias：组件昵称
  * @param[in]  addr：地址
  * @param[in]  out_data：数据指针
  * @param[in]  len：数据长度
  * 
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误）
  */
ErrorStatus OSAL_NvReadGlobal(uint16_t comp_id, uint8_t alias, uint32_t addr, void *out_data, uint32_t len)
{
    APPSS_ASSERT(g_ActiveAppIndex != APP_NO_APP);

    /* 优先获取本地TASK-LIST里面的nv数据 */
    uint32_t nv_addr, nv_size;
    if (OSAL_NvGetInfo(comp_id, alias, &nv_addr, &nv_size) == SUCCESS)
    {
        if ((nv_size > 0) && (addr + len <= nv_size))
        {
            if (Device_Read(vEEPROM_0, out_data, len, nv_addr + addr) >= 0)
            {
                return SUCCESS;
            }
        }
    }

    /* 其次获取虚拟TASK-LIST里面的NV数据 */
    for (int i = 0; i < OSPORT_MAX_QTY; i++)
    {
        for (int j = 0; j < vTaskList[i].qty; j++)
        {
            if ((comp_id == vTaskList[i].list[j].comp_id) && 
                ((0 == vTaskList[i].list[j].alias) || (alias == vTaskList[i].list[j].alias)))
            {
                if (addr + len <= vTaskList[i].list[j].nv_size)
                {
                    memcpy(out_data, vTaskList[i].list[j].nv_data + addr, len);
                    return SUCCESS;
                }
            }
        }
    }
    return ERROR;
}

/**
  * @brief  发送TASK-INFO给主机
  * @details 详细说明: 如果编译了本函数说明当前是主机（主机端不需要发出TASK-INFO数据）       
  * 
  * @param[in] task_index:
  * 
  * @return NULL
  */
void OSAL_SendSync(uint8_t task_index, uint32_t rm, uint32_t rs)
{
    ;
}
#endif

/**
  * @brief  检查所有TASK的状态
  * @details 详细说明:无
  * 
  * @return NULL  
  */
static ErrorStatus OSAL_TaskStatusCheck(void)
{
#if !defined(KOS_PARAM_ROLE_SLAVE)
    /* 检查虚拟（子系统）TASK状态 */
    for (int i = 0; i < OSPORT_MAX_QTY; i++)
    {
        for (int j = 0; j < vTaskList[i].qty; j++)
        {
            if ((vTaskList[i].list[j].status == TASK_STA_ACTIVE) && ((vTaskList[i].port >> 8) != vBLE))
            {
                __OSAL_LOG("[osal.c] sleep failed, vTask is active, port:%04X, comp_id: %d\r\n", vTaskList[i].port, vTaskList[i].list[j].comp_id);
                return ERROR;
            }
        }
    }
#endif
    /* 检查本地TASK状态 */
    return OSAL_TaskStatusCheckLocal();
}

/**
  * @brief  睡眠前的检查（主机端）
  * @details
  *         
  * @param[in]  delay:当前设定的自动休眠的值ms
  * 
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误）
  */
ErrorStatus OSAL_SleepCheck(uint32_t *delay)
{
    //< MSG-LIST不为空：禁止睡眠
    if (pMessageList->next != NULL)
    {
        OSAL_UpdateSleepTime(1000, 1);
        return ERROR;
    }

    //< 某个TASK状态为ACTIVE：禁止睡眠
    if (OSAL_TaskStatusCheck() != SUCCESS)
    {
        OSAL_UpdateSleepTime(1000, 1);
        return ERROR;
    }

    //< 应用层逻辑不允许休眠：禁止睡眠
    if (OSAL_SleepCallbackApp() != SUCCESS)
    {
        OSAL_UpdateSleepTime(*delay, 1);
        return ERROR;
    }
    return SUCCESS;
}
